/*
 * @Description:
 * @Author: maxyang
 * @Date: 2022-05-16 21:07:20
 * @LastEditTime: 2022-08-09 22:20:11
 * @LastEditors: liutq
 * @Reference:
 */
package user

import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/maxyang107/jinglan/common"
	"github.com/maxyang107/jinglan/model"
	"github.com/maxyang107/jinglan/model/goods"
	"github.com/maxyang107/jinglan/model/system"
)

type User struct {
	ID         uint   `gorm:"column:id; parimary_key" json:"id"`
	Username   string `gorm:"column:username" json:"username" `
	HeadImg    string `gorm:"column:headimg" json:"headimg" `
	Password   string `gorm:"column:password" json:"password" binding:"required"`
	Salt       string `gorm:"column:salt" json:"salt"`
	Phone      int64  `gorm:"column:phone" json:"phone" binding:"required"`
	Idnum      string `gorm:"column:idnum" json:"idnum"`
	Status     uint8  `gorm:"column:status" json:"status"`
	InviteCode string `gorm:"column:invite_code" json:"invite_code"`
	Fromuid    uint   `gorm:"column:from_uid" json:"from_uid"`
	RankNum    uint   `gorm:"column:rank_num" json:"rank_num"`
	LuckyNum   uint   `gorm:"column:lucky_num" json:"lucky_num"`
	Role       uint8  `gorm:"column:role" json:"role"`
}

type UserInvite struct {
	ID       uint      `gorm:"column:id; parimary_key" json:"id"`
	Phone    string    `gorm:"column:phone" json:"phone"`
	HeadImg  string    `gorm:"column:headimg" json:"headimg" `
	CreateAt time.Time `gorm:"column:create_at" json:"create_at"`
}

type UserInviteList struct {
	Page    int
	PerPage int
	Total   int
	Data    []UserInvite
}

type Rank struct {
	ID       uint   `gorm:"column:id; parimary_key" json:"id"`
	Username string `gorm:"column:username" json:"username" `
	HeadImg  string `gorm:"column:headimg" json:"headimg" `
	Phone    string `gorm:"column:phone" json:"phone"`
	RankNum  uint   `gorm:"column:rank_num" json:"rank_num"`
}

type RankInviteList struct {
	Page    int
	PerPage int
	Total   int
	Data    []Rank
}

type UserList struct {
	Page    int
	PerPage int
	Total   int
	Data    []User
}

func FindUserByPhone(phone int64) *User {
	user := &User{}
	model.Db.Where(&User{Phone: phone}).First(&user)
	return user
}

func FindUserByInviteCode(invitecode string) *User {
	user := &User{}
	model.Db.Where(&User{InviteCode: invitecode}).First(&user)
	return user
}

func FindUserByUserId(userId uint) *User {
	user := &User{}
	model.Db.Where(&User{ID: userId}).First(&user)
	return user
}

func Register(register_ *User) error {

	var tmp_ User

	model.Db.Where(&User{Phone: register_.Phone}).Or(&User{Idnum: register_.Idnum}).First(&tmp_)

	if tmp_.ID > 0 {
		return errors.New("用户已存在")
	}

	if register_.Fromuid > 0 {
		model.Db.Where(&User{ID: register_.Fromuid}).Update("rank_num", gorm.Expr("rank_num + ?", 1))
		var user_ User
		model.Db.Where(&User{ID: register_.Fromuid}).First(&user_)
		//检查邀请人数赠送空投条件
		sc2 := system.GetSysConfigDetail(common.INVITEAIRDROP)

		var airdropconf []map[string]interface{}
		json.Unmarshal([]byte(sc2.ConfigValue), &airdropconf)

		for _, v := range airdropconf {
			fmt.Println(reflect.TypeOf(v["rank_num"]))
			rank_num_ := reflect.ValueOf(v["rank_num"])

			var ranknum uint
			if rank_num_.Interface().(float64) == rank_num_.Float() {
				ranknum = uint(float64(rank_num_.Float()))
			}
			//等于的时候自动赠送空投
			if user_.RankNum == ranknum && ranknum > 0 {
				//获取库存
				goodsid := reflect.ValueOf(v["goodsid"]).Uint()

				gt := goods.GetGoodsDetail(int(goodsid))
				//库存足够的时候进行空投
				if gt.GoodsStore > 0 {
					model.Db.Model(&goods.Goods{}).Where(&goods.Goods{ID: uint(goodsid)}).Update(&goods.Goods{GoodsStore: gt.GoodsStore - 1})

					Buildcollect(&gt, register_.ID, 2, "", 1, 1)
				}
				break
			}
		}

	}

	if err := model.Db.Create(&register_).Error; err != nil {
		return err
	}
	//注册成功后赠送空投
	sc := system.GetSysConfigDetail(common.REGISTERAIRDROP)
	m := make(map[string]interface{})
	json.Unmarshal([]byte(sc.ConfigValue), &m)

	v := reflect.ValueOf(m["exptime"]).String()
	tm, _ := time.Parse("2006-01-02", v)
	if tm.After(time.Now()) {
		//获取库存
		goodsid := reflect.ValueOf(m["goodsid"]).Uint()

		gt := goods.GetGoodsDetail(int(goodsid))

		if gt.GoodsStore > 0 {
			model.Db.Model(&goods.Goods{}).Where(&goods.Goods{ID: uint(goodsid)}).Update(&goods.Goods{GoodsStore: gt.GoodsStore - 1})

			Buildcollect(&gt, register_.ID, 2, "", 1, 1)
		}
	}
	//如果邀请人存在自增
	if register_.Fromuid > 0 {
		var yq User
		model.Db.Where(&User{ID: uint(register_.Fromuid)}).First(&yq)

		yq.RankNum = yq.RankNum + 1

		model.Db.Model(&User{}).Update(&yq)
	}
	return nil
}

func FindUserByPhoneOrIdnum(phone int64, idnum string) *User {
	user := &User{}
	where := []interface{}{
		[]interface{}{"phone", "=", phone},
		[]interface{}{"idnum", "=", "idnum", "or"},
	}

	model.Db.Where(where).First(&user)
	return user
}

func GetUserByPhone(phone int64) *User {
	user := &User{}
	model.Db.Where(&User{Phone: phone}).First(&user)
	return user
}

func GetInviteList(query_ common.AnnouncementList) *UserInviteList {
	var invitelist UserInviteList
	invitelist.Total = getTotal(query_)
	invitelist.Page = query_.Page
	invitelist.PerPage = query_.PerPage

	model.Db.Model(&User{}).Where(&User{Fromuid: uint(query_.UserId)}).Limit(query_.PerPage).Offset((query_.Page - 1) * query_.PerPage).Scan(&invitelist.Data)
	return &invitelist
}

func getTotal(query_ common.AnnouncementList) int {
	key := strconv.Itoa(int(query_.UserId)) + "invitelist"

	s := model.GetKey(key)
	pageNum_, _ := strconv.Atoi(s)
	if pageNum_ > 0 {
		return int(pageNum_)
	}
	var total int
	model.Db.Model(&User{}).Where(&User{Fromuid: uint(query_.UserId)}).Count(&total)
	pageNum := total / query_.PerPage
	if total%query_.PerPage != 0 {
		pageNum++
	}
	model.SetKey(key, strconv.Itoa(int(pageNum)), 300*time.Second)
	return pageNum
}

func GetInviteRankList(query_ common.AnnouncementList) *RankInviteList {
	var ranklist RankInviteList
	ranklist.Total = getRankTotal(query_)
	ranklist.Page = query_.Page
	ranklist.PerPage = query_.PerPage
	model.Db.Model(&User{}).Order("rank_num desc").Where("rank_num > 0").Limit(query_.PerPage).Offset((query_.Page - 1) * query_.PerPage).Scan(&ranklist.Data)

	return &ranklist
}

func getRankTotal(query_ common.AnnouncementList) int {
	key := strconv.Itoa(int(query_.UserId)) + "Ranklist"

	s := model.GetKey(key)
	pageNum_, _ := strconv.Atoi(s)
	if pageNum_ > 0 {
		return int(pageNum_)
	}
	var total int
	model.Db.Model(&User{}).Where("rank_num > 0").Count(&total)
	pageNum := total / query_.PerPage
	if total%query_.PerPage != 0 {
		pageNum++
	}
	model.SetKey(key, strconv.Itoa(int(pageNum)), 300*time.Second)
	return pageNum
}

func GetUserList(param common.UserList) *UserList {
	var userlist UserList

	userlist.Page = param.Page
	userlist.PerPage = param.PerPage
	userlist.Total = getUserListTotal(param)
	tx := model.Db.Model(&User{})
	if param.Key != "" {
		tx = tx.Where(fmt.Sprintf(" username like %s or phone like %s ", ("'%" + param.Key + "%'"), ("'%" + param.Key + "%'")))
	}

	if param.RankSort != "" {
		tx = tx.Order(fmt.Sprintf("rank_num %s", param.RankSort))
	}

	tx.Limit(param.PerPage).Offset((param.Page - 1) * param.PerPage).Scan(&userlist.Data)

	return &userlist
}

func getUserListTotal(query_ common.UserList) int {

	var total int
	tx := model.Db.Model(&User{})
	if query_.Key != "" {
		tx = tx.Where(fmt.Sprintf(" username like %s or phone like %s ", ("'%" + query_.Key + "%'"), ("'%" + query_.Key + "%'")))
	}
	tx.Count(&total)

	return total
}

func SetUserStatus(id uint, sutaus uint8) error {
	values := map[string]interface{}{
		"id":     id,
		"status": sutaus,
	}
	if err := model.Db.Model(&User{}).Update(values).Error; err != nil {
		fmt.Println(err.Error())
		return err
	}
	return nil
}

func ModifyPassword(user *User) error {
	if err := model.Db.Model(&User{}).Select("password").Where(&User{ID: user.ID}).Update(user).Error; err != nil {
		return err
	}
	return nil
}

func ModifyLuckyNumber(user *User) error {
	if err := model.Db.Model(&User{}).Select("lucky_num").Where(&User{ID: user.ID}).Update(user).Error; err != nil {
		return err
	}
	return nil
}

func addLuckyNum(userId uint, addnum uint) {
	if addnum == 0 {
		return
	}
	u := FindUserByUserId(userId)
	u.LuckyNum = u.LuckyNum + addnum
	ModifyLuckyNumber(u)
}
